﻿#include "LogicSys.h"
#include "StatusGrpcClient.h"
#include "mysqlMgr.h"
#include "RedisMgr.h"
#include "const.h"
#include "UserMgr.h"
#include "ChatGrpcClient.h"
LogicSys& LogicSys::GetInst()
{
	static LogicSys instance;
	return instance;
}

LogicSys::~LogicSys()
{
	std::cout << "~LogicSys" << std::endl;
}
LogicSys::LogicSys() {
	_work_thread = std::thread(&LogicSys::dealMsg, this);
	RegisterCallBack();
}
void LogicSys::PostMsgToQue(std::shared_ptr<LogicNode> msg)
{
	std::unique_lock<std::mutex> lock(_mtx);
	_logic_que.push(msg);
	if (_logic_que.size() == 1)
	{
		lock.unlock();
		_cond_var.notify_one();
	}
}

void LogicSys::RegisterCallBack()
{
	_func_callbacks[MSG_CHAT_LOGIN] = std::bind(&LogicSys::LoginHandler, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	_func_callbacks[ID_SEARCH_USER_REQ] = std::bind(&LogicSys::SearchInfo, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	_func_callbacks[ID_ADD_FRIEND_REQ] = std::bind(&LogicSys::AddFriendApply, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	_func_callbacks[ID_AUTH_FRIEND_REQ] = std::bind(&LogicSys::AuthFriendApply, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
	_func_callbacks[ID_TEXT_CHAT_MSG_REQ] = std::bind(&LogicSys::DealChatTextMsg, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}

void LogicSys::dealMsg()
{
	while (true)
	{
		std::unique_lock<std::mutex> lock(_mtx);
		//队列为空且未退出则等待
		if (_logic_que.empty() && !_b_stop)
		{
			_cond_var.wait(lock);
		}
		//关闭状态下，将所有消息处理后结束
		if (_b_stop)
		{
			while (!_logic_que.empty())
			{
				auto& msgnode = _logic_que.front();
				std::cout << "recv msg id :" << msgnode->_recv_node->GetMsgId() << std::endl;
				auto call_back_iter = _func_callbacks.find(msgnode->_recv_node->GetMsgId());
				if (call_back_iter == _func_callbacks.end())
				{
					_logic_que.pop();
					std::cerr << msgnode->_recv_node->GetMsgId() << "Handler not Found" << std::endl;
					continue;
				}
				call_back_iter->second(msgnode->_session, msgnode->_recv_node->GetMsgId(), std::string(msgnode->_recv_node->_data, msgnode->_recv_node->_len));
				_logic_que.pop();
			}
			break;
		}

		auto msgnode = _logic_que.front();
		std::cout << "recv msg id :" << msgnode->_recv_node->GetMsgId() << std::endl;
		auto call_back_iter = _func_callbacks.find(msgnode->_recv_node->GetMsgId());
		if (call_back_iter == _func_callbacks.end())
		{
			_logic_que.pop();
			std::cerr << msgnode->_recv_node->GetMsgId() << "Handler not Found" << std::endl;
			return;
		}
		call_back_iter->second(msgnode->_session, msgnode->_recv_node->GetMsgId(), std::string(msgnode->_recv_node->_data, msgnode->_recv_node->_len));
		_logic_que.pop();
	}
}

bool LogicSys::isPureDigit(const std::string& str)
{
	for (char c : str)
	{
		if (!std::isdigit(c))
		{
			return false;
		}
	}
	return true;
}

void LogicSys::GetUserByUid(std::string uid_str, Json::Value& rtvalue)
{
	rtvalue["error"] = ErrorCodes::Success;
	std::string base_key = USER_BASE_INFO + uid_str;
	std::string info_str = "";
	bool b_base = RedisMgr::GetInstance().Get(base_key, info_str);
	if (b_base)
	{
		Json::Reader reader;
		Json::Value root;
		reader.parse(info_str, root);
		auto uid = root["uid"].asInt();
		auto name = root["name"].asString();
		auto pwd = root["pwd"].asString();
		auto email = root["email"].asString();
		auto nick = root["nick"].asString();
		auto desc = root["desc"].asString();
		auto sex = root["sex"].asInt();
		auto icon = root["icon"].asString();

		std::cout << "uid:" << uid;

		rtvalue["uid"] = uid;
		rtvalue["pwd"] = pwd;
		rtvalue["name"] = name;
		rtvalue["email"] = email;
		rtvalue["nick"] = nick;
		rtvalue["desc"] = desc;
		rtvalue["sex"] = sex;
		rtvalue["icon"] = icon;
		return;
	}
	auto uid = std::stoi(uid_str);

	std::shared_ptr<UserInfo> user_info = nullptr;
	user_info = mysqlMgr::GetInst().GetUser(uid);
	if (user_info == nullptr)
	{
		rtvalue["error"] = ErrorCodes::UidInvalid;
		return;
	}

	Json::Value redis_root;
	redis_root["uid"] = uid;
	redis_root["pwd"] = user_info->pwd;
	redis_root["name"] = user_info->name;
	redis_root["email"] = user_info->email;
	redis_root["nick"] = user_info->nick;
	redis_root["desc"] = user_info->desc;
	redis_root["sex"] = user_info->sex;
	redis_root["icon"] = user_info->icon;
	
	RedisMgr::GetInstance().Set(base_key, redis_root.toStyledString());

	rtvalue["uid"] = uid;
	rtvalue["pwd"] = user_info->pwd;
	rtvalue["name"] = user_info->name;
	rtvalue["email"] = user_info->email;
	rtvalue["nick"] = user_info->nick;
	rtvalue["desc"] = user_info->desc;
	rtvalue["sex"] = user_info->sex;
	rtvalue["icon"] = user_info->icon;
}

void LogicSys::GetUserByName(std::string name_str, Json::Value& rtvalue)
{

	rtvalue["error"] = ErrorCodes::Success;
	std::string base_key = USER_BASE_INFO + name_str;
	std::string info_str = "";
	bool b_base = RedisMgr::GetInstance().Get(base_key, info_str);
	if (b_base)
	{
		Json::Reader reader;
		Json::Value root;
		reader.parse(info_str, root);
		auto uid = root["uid"].asString();
		auto name = root["name"].asString();
		auto pwd = root["pwd"].asString();
		auto email = root["email"].asString();
		auto nick = root["nick"].asString();
		auto desc = root["desc"].asString();
		auto sex = root["sex"].asInt();
		auto icon = root["icon"].asString();

		std::cout << "uid:" << uid;

		rtvalue["uid"] = uid;
		rtvalue["pwd"] = pwd;
		rtvalue["name"] = name;
		rtvalue["email"] = email;
		rtvalue["nick"] = nick;
		rtvalue["desc"] = desc;
		rtvalue["sex"] = sex;
		rtvalue["icon"] = icon;
		return;
	}

	std::shared_ptr<UserInfo> user_info = nullptr;
	user_info = mysqlMgr::GetInst().GetUser(name_str);
	if (user_info == nullptr)
	{
		rtvalue["error"] = ErrorCodes::UidInvalid;
		return;
	}

	Json::Value redis_root;
	redis_root["uid"] = user_info->uid;
	redis_root["pwd"] = user_info->pwd;
	redis_root["name"] = user_info->name;
	redis_root["email"] = user_info->email;
	redis_root["nick"] = user_info->nick;
	redis_root["desc"] = user_info->desc;
	redis_root["sex"] = user_info->sex;
	redis_root["icon"] = user_info->icon;

	RedisMgr::GetInstance().Set(base_key, redis_root.toStyledString());

	rtvalue["uid"] = user_info->uid;
	rtvalue["pwd"] = user_info->pwd;
	rtvalue["name"] = user_info->name;
	rtvalue["email"] = user_info->email;
	rtvalue["nick"] = user_info->nick;
	rtvalue["desc"] = user_info->desc;
	rtvalue["sex"] = user_info->sex;
	rtvalue["icon"] = user_info->icon;
}

void LogicSys::LoginHandler(std::shared_ptr<CSession> session, const short& msg_id, const std::string& msg_data)
{
	Json::Value root;
	Json::Reader reader;
	reader.parse(msg_data, root);
	auto uid = root["uid"].asInt();
	auto token = root["token"].asString();
	std::cout << "user login uid:" << uid << "user token:" << root["token"].asString() << std::endl;
	auto rsp = StatusGrpcClient::GetInst().Login(uid, root["token"].asString());
	Json::Value rtvalue;
	Defer defer([this, &rtvalue, session]() {
		std::string return_str = rtvalue.toStyledString();
		session->Send(return_str, return_str.length(), MSG_CHAT_LOGIN_RSP);
		});
	

	//rtvalue["error"] = rsp.error();
	//if (rsp.error() != ErrorCodes::Success)
	//{
	//	return;
	//}
	//std::string return_str = rtvalue.toStyledString();
	//session->Send(return_str, return_str.length(), MSG_CHAT_LOGIN_RSP); 
	//std::shared_ptr<UserInfo> user_info = nullptr;


//从redis获取用户token是否正确
	std::string uid_str = std::to_string(uid);
	std::string token_key = USERTOKENPREFIX + uid_str;
	std::string token_value = "";
	bool success = RedisMgr::GetInstance().Get(token_key, token_value);
	if (!success) {
		rtvalue["error"] = ErrorCodes::UidInvalid;
		return;
	}

	if (token_value != token) {
		rtvalue["error"] = ErrorCodes::TokenInvalid;
		return;
	}

	rtvalue["error"] = ErrorCodes::Success;

	std::string base_key = USER_BASE_INFO + uid_str;
	auto user_info = std::make_shared<UserInfo>();
	bool b_base = GetBaseInfo(base_key, uid, user_info);
	if (!b_base) {
		rtvalue["error"] = ErrorCodes::UidInvalid;
		return;
	}
	rtvalue["uid"] = uid;
	rtvalue["pwd"] = user_info->pwd;
	rtvalue["name"] = user_info->name;
	rtvalue["email"] = user_info->email;
	rtvalue["nick"] = user_info->nick;
	rtvalue["desc"] = user_info->desc;
	rtvalue["sex"] = user_info->sex;
	rtvalue["icon"] = user_info->icon;

	//从数据库获取申请列表
	std::vector<std::shared_ptr<ApplyInfo>> apply_list;
	auto b_apply = GetFriendApplyInfo(uid, apply_list);
	if (b_apply)
	{
		for (auto& apply : apply_list)
		{
			Json::Value obj;
			obj["name"] = apply->_name;
			obj["uid"] = apply->_uid;
			obj["icon"] = apply->_icon;
			obj["nick"] = apply->_nick;
			obj["sex"] = apply->_sex;
			obj["desc"] = apply->_desc;
			obj["status"] = apply->_status;
			rtvalue["apply_list"].append(obj);
		}
	}
	//获取好友列表

	std::vector<std::shared_ptr<UserInfo>> friend_list;
	bool b_friend_list = GetFriendList(uid, friend_list);
	for (auto& friend_ele : friend_list)
	{
		Json::Value obj;
		obj["name"] = friend_ele->name;
		obj["uid"] = friend_ele->uid;
		obj["icon"] = friend_ele->icon;
		obj["nick"] = friend_ele->nick;
		obj["sex"] = friend_ele->sex;
		obj["desc"] = friend_ele->desc;
		rtvalue["friend_ele_list"].append(obj);
	}

	auto server_name = configMgr::GetInst().GetValue("SelfServer", "Name");
	//将登录数量增加
	auto rd_res = RedisMgr::GetInstance().HGet(LOGIN_COUNT, server_name);
	int count = 0;
	if (!rd_res.empty()) {
		count = std::stoi(rd_res);
	}

	count++;

	auto count_str = std::to_string(count);
	RedisMgr::GetInstance().HSet(LOGIN_COUNT, server_name, count_str);

	//session绑定用户uid
	session->SetUserId(uid);

	//为用户设置登录ip server的名字
	std::string  ipkey = USERIPPREFIX + uid_str;
	RedisMgr::GetInstance().Set(ipkey, server_name);

	//uid和session绑定管理,方便以后踢人操作
	UserMgr::GetInst().SetUserSession(uid, session);

	return;

}

void LogicSys::SearchInfo(std::shared_ptr<CSession> session, const short& msg_id, const std::string& msg_data)
{
	Json::Reader reader;
	Json::Value root;
	reader.parse(msg_data, root);
	auto uid_str = root["uid"].asString();
	std::cout << "user SearchInfo uid is" << uid_str << std::endl;
	Json::Value rtvalue;
	Defer defer([this, &rtvalue, session] (){
		std::string return_str = rtvalue.toStyledString();
		session->Send(return_str, return_str.length(), ID_SEARCH_USER_RSP);
		});

	bool b_digit = isPureDigit(uid_str);
	if (b_digit)
	{
		GetUserByUid(uid_str, rtvalue);
	}
	else {
		GetUserByName(uid_str, rtvalue);
	}

}

bool LogicSys::GetFriendApplyInfo(int uid, std::vector<std::shared_ptr<ApplyInfo>>& apply_list)
{
	return mysqlMgr::GetInst().GetApplyList(uid, apply_list,0,10);
}

void LogicSys::AddFriendApply(std::shared_ptr<CSession> session, const short& msg_id, const std::string& msg_data)
{
	Json::Reader reader;
	Json::Value root;
	reader.parse(msg_data, root);
	auto uid = root["uid"].asInt();
	auto applyname = root["applyname"].asString();
	auto backname = root["backname"].asString();
	auto touid = root["touid"].asInt();
	std::cout << "user login uid:" << uid << std::endl;
	Json::Value rtvalue;
	rtvalue["error"] = ErrorCodes::Success;
	Defer defer([this, &rtvalue, session]() {
		std::string return_str = rtvalue.toStyledString();
		session->Send(return_str, return_str.length(), ID_ADD_FRIEND_RSP);
		});
	//更新数据库
	mysqlMgr::GetInst().AddFriendApply(uid, touid);

	auto to_str = std::to_string(touid);
	auto to_ip_key = USERIPPREFIX + to_str;
	std::string to_ip_value = "";
	bool b_ip = RedisMgr::GetInstance().Get(to_ip_key, to_ip_value);
	if (!b_ip)
	{
		return;
	}
	auto& cfg = configMgr::GetInst();
	auto self_name = cfg["SelfServer"]["Name"];

	if (to_ip_value == self_name)
	{
		auto session = UserMgr::GetInst().GetSession(touid);
		if (session)
		{
			Json::Value notify;
			notify["error"] = ErrorCodes::Success;
			notify["applyuid"] = uid;
			notify["name"] = applyname;
			notify["desc"] = "";
			std::string return_str = notify.toStyledString();
			session->Send(return_str, return_str.length(), ID_NOTIFY_ADD_FRIEND_REQ);

		}
		return;
	}

	std::string base_key = USER_BASE_INFO + std::to_string(uid);
	auto apply_info = std::make_shared<UserInfo>();
	bool b_info = GetBaseInfo(base_key,uid,apply_info);

	message::AddFriendReq add_req;
	add_req.set_applyuid(uid);
	add_req.set_touid(touid);
	add_req.set_name(applyname);
	add_req.set_desc("");
	if (b_info)
	{
		add_req.set_icon(apply_info->icon);
		add_req.set_sex(apply_info->sex);
		add_req.set_nick(apply_info->nick);
	}
	//发送通知
	ChatGrpcClient::GetInst().NotifyAddFriend(to_ip_value, add_req);

}

void LogicSys::AuthFriendApply(std::shared_ptr<CSession> session, const short& msg_id, const std::string& msg_data)
{
	Json::Reader reader;
	Json::Value root;
	reader.parse(msg_data, root);
	auto uid = root["fromuid"].asInt();
	auto backname = root["back"].asString();
	auto touid = root["touid"].asInt();
	std::cout << "from uid:" << uid <<"to uid" <<touid << std::endl;
	Json::Value rtvalue;
	rtvalue["error"] = ErrorCodes::Success;
	auto user_info = std::make_shared<UserInfo>();

	std::string base_key = USER_BASE_INFO + std::to_string(touid);
	bool b_info = GetBaseInfo(base_key, touid,user_info);
	if (b_info)
	{
		rtvalue["name"] = user_info->name;
		rtvalue["nick"] = user_info->nick;
		rtvalue["icon"] = user_info->icon;
		rtvalue["sex"] = user_info->sex;
		rtvalue["uid"] = touid;
	}
	else
	{
		rtvalue["error"] = ErrorCodes::UidInvalid;
	}

	Defer defer([this, &rtvalue, session]() {
		std::string return_str = rtvalue.toStyledString();
		session->Send(return_str, return_str.length(), ID_AUTH_FRIEND_RSP);
		});

	// 先更新数据库
	mysqlMgr::GetInst().AuthFriendApply(uid, touid);

	//更新数据库添加好友
	mysqlMgr::GetInst().AddFriend(uid, touid, backname);

	auto to_str = std::to_string(touid);
	auto to_ip_key = USERIPPREFIX + to_str;
	
	//查询Redis查找touid对应Sever
	std::string to_ip_value = "";
	bool b_ip = RedisMgr::GetInstance().Get(to_ip_key,to_ip_value);
	if (!b_ip)
	{
		return;
	}

	auto& cfg = configMgr::GetInst();
	auto self_name = cfg["SelfServer"]["Name"];

	if (to_ip_value == self_name)
	{
		auto session = UserMgr::GetInst().GetSession(touid);
		if (session)
		{
			Json::Value notify;
			notify["error"] = ErrorCodes::Success;
			notify["fromuid"] = uid;
			notify["touid"] = touid;
			std::string base_key = USER_BASE_INFO + std::to_string(uid);
			auto user_info = std::make_shared<UserInfo>();
			bool b_info = GetBaseInfo(base_key, uid, user_info);
			if (b_info)
			{
				notify["name"] = user_info->name;
				notify["nick"] = user_info->nick;
				notify["icon"] = user_info->icon;
				notify["sex"] = user_info->sex;
			}
			else {
				notify["error"] = ErrorCodes::UidInvalid;
			}
			std::string return_str = notify.toStyledString();
			session->Send(return_str, return_str.length(), ID_NOTIFY_AUTH_FRIEND_REQ);
		}
		return;
	}

	message::AuthFriendReq auth_req;
	auth_req.set_fromuid(uid);
	auth_req.set_touid(touid);

	//发送通知
	ChatGrpcClient::GetInst().NotifyAuthFriend(to_ip_value, auth_req);


}

void LogicSys::DealChatTextMsg(std::shared_ptr<CSession> session, const short& msg_id, const std::string& msg_data)
{
	Json::Reader reader;
	Json::Value root;
	reader.parse(msg_data, root);

	auto uid = root["fromuid"].asInt();
	auto touid = root["touid"].asInt();

	const Json::Value  arrays = root["text_array"];

	Json::Value  rtvalue;
	rtvalue["error"] = ErrorCodes::Success;
	rtvalue["text_array"] = arrays;
	rtvalue["fromuid"] = uid;
	rtvalue["touid"] = touid;

	Defer defer([this, &rtvalue, session]() {
		std::string return_str = rtvalue.toStyledString();
		session->Send(return_str, return_str.length(), ID_TEXT_CHAT_MSG_RSP);
		});


	//��ѯredis ����touid��Ӧ��server ip
	auto to_str = std::to_string(touid);
	auto to_ip_key = USERIPPREFIX + to_str;
	std::string to_ip_value = "";
	bool b_ip = RedisMgr::GetInstance().Get(to_ip_key, to_ip_value);
	if (!b_ip) {
		return;
	}

	auto& cfg = configMgr::GetInst();
	auto self_name = cfg["SelfServer"]["Name"];
	//ֱ��֪ͨ�Է�����֤ͨ����Ϣ
	if (to_ip_value == self_name) {
		auto session = UserMgr::GetInst().GetSession(touid);
		if (session) {
			//���ڴ�����ֱ�ӷ���֪ͨ�Է�
			std::string return_str = rtvalue.toStyledString();
			session->Send(return_str, return_str.length(), ID_NOTIFY_TEXT_CHAT_MSG_REQ);
		}

		return;
	}


	message::TextChatMsgReq text_msg_req;
	text_msg_req.set_fromuid(uid);
	text_msg_req.set_touid(touid);
	for (const auto& txt_obj : arrays) {
		auto content = txt_obj["content"].asString();
		auto msgid = txt_obj["msgid"].asString();
		std::cout << "content is " << content << std::endl;
		std::cout << "msgid is " << msgid << std::endl;
		auto* text_msg = text_msg_req.add_textmsgs();
		text_msg->set_msgid(msgid);
		text_msg->set_msgcontent(content);
	}


	//发送通知
	ChatGrpcClient::GetInst().NotifyTextChatMsg(to_ip_value, text_msg_req, rtvalue);
	
}

bool LogicSys::GetBaseInfo(std::string base_key, int uid, std::shared_ptr<UserInfo>& user_info)
{
	std::string info_str = "";
	bool b_base = RedisMgr::GetInstance().Get(base_key, info_str);
	if (b_base) {
		Json::Reader  reader;
		Json::Value root;
		reader.parse(info_str, root);
		user_info->uid = root["uid"].asInt();
		user_info->name = root["name"].asString();
		user_info->pwd = root["pwd"].asString();
		user_info->email = root["email"].asString();
		user_info->nick = root["nick"].asString();
		user_info->desc = root["desc"].asString();
		user_info->sex = root["sex"].asInt();
		user_info->icon = root["icon"].asString();
		std::cout << "user login uid :" << user_info->uid << "name:" << user_info->name << std::endl;
	}
	else {
		std::shared_ptr<UserInfo> userinfo = nullptr;
		userinfo = mysqlMgr::GetInst().GetUser(uid);
		if (user_info == nullptr)
		{
			return false;
		}
		user_info = userinfo;
		Json::Value redis_root;
		redis_root["uid"] = uid;
		redis_root["pwd"] = userinfo->pwd;
		redis_root["name"] = userinfo->name;
		redis_root["email"] = userinfo->email;
		redis_root["nick"] = userinfo->nick;
		redis_root["sex"] = userinfo->sex;
		redis_root["icon"] = userinfo->icon;
		RedisMgr::GetInstance().Set(base_key, redis_root.toStyledString());
	}
	return true;
}

bool LogicSys::GetFriendList(int self_uid, std::vector<std::shared_ptr<UserInfo>>& user_list)
{
	return mysqlMgr::GetInst().GetFriendList(self_uid, user_list);
}
